﻿using System;
using System.Collections.Generic;
using System.Linq;
using Common.Logging;
using Newtonsoft.Json;
using User.Api.Helpers.WeixinPayV3;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Xml.Serialization;
using System.IO;
using User.Api.Helpers.WeixinPayV3.WxResult;
using User.Api.Helpers.WeixinPayV3.Message;
using Newtonsoft.Json.Linq;
using Senparc.Weixin.MP.CommonAPIs;
using System.Xml;
using System.Configuration;
using OutDbContext;

namespace User.Api.Helpers
{
    public class WeixinPayV3Helper
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(WeixinPayV3Helper));
 
        public static ComposeJsApiParameterResult ComposeJsApiParameter(string tradeType, string tradeName, string tradeNo, string totalFee, string clientIp, string startTime, string expireTime, string notifyControllerAction, string openId)
        {
            //profile.AppId = "wx5310abead5afee7a";
            //profile.MchId = "10037312";
            //profile.TenPayPartnerKey = "0ddafd94abdc9d552b1a1fd854472f84";

            //prepayid 只有第一次支付时生成，如果需要再次支付，必须拿之前生成的prepayid。
            //也就是说一个orderNo 只能对应一个prepayid
            string prepayid = string.Empty;
            if (string.IsNullOrEmpty(tradeType))
            {
                tradeType = "JSAPI"; //设置默认交易类型
            }
            //创建Model
            var model = UnifiedWxPayModel.CreateUnifiedModel(WeixinPayV3Info.AppId, WeixinPayV3Info.MchId, WeixinPayV3Info.Key);
            try
            {
                var url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
                var postData = model.CreatePrePayPackage(tradeType, tradeName, tradeNo, totalFee,
                   clientIp, startTime, expireTime, WeixinPayV3Info.TenPayV3Notify + notifyControllerAction, openId);
                var httpClient = new HttpClient();
                var httpContent = new StringContent(postData);
                httpContent.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
                var response = httpClient.PostAsync(url, httpContent).Result.Content.ReadAsStringAsync().Result;
                var xmlSerializer = new XmlSerializer(typeof(UnifiedPrePayMessage));
                var result = (UnifiedPrePayMessage)(xmlSerializer.Deserialize(new StringReader(response)));
                if (tradeType.ToUpper() != "NATIVE")
                {
                    if (result == null
                    || !result.ReturnSuccess
                    || !result.ResultSuccess
                    || string.IsNullOrEmpty(result.Prepay_Id))
                    {
                        return new ComposeJsApiParameterResult()
                        {
                            ResultCode = "1",
                            ResultMsg = "获取PrepayId 失败,错误代码" + result.Return_Code + ",错误信息：" + result.Return_Msg
                        };
                    }

                    //预支付订单
                    prepayid = result.Prepay_Id;
                    var package = string.Format("prepay_id={0}", prepayid);
                    var timestamp = ((DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000).ToString();
                    var nonceStr = CommonUtil.CreateNoncestr();
                    //JSAPI 支付参数的Model
                    var nativeObj = new Dictionary<string, string>();
                    nativeObj.Add("appId", WeixinPayV3Info.AppId);
                    nativeObj.Add("package", package);
                    nativeObj.Add("timeStamp", timestamp);
                    nativeObj.Add("nonceStr", nonceStr);
                    nativeObj.Add("signType", "MD5");
                    var payModel = new
                    {
                        appId = model.AppId,
                        package = package,
                        timeStamp = timestamp,
                        nonceStr = nonceStr,
                        signType = "MD5",
                        paySign = model.GetCftPackage(nativeObj)//生成JSAPI 支付签名
                    };

                    return new ComposeJsApiParameterResult()
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        Parameter = JsonConvert.SerializeObject(payModel)
                    };
                }
                else //Native
                {
                    if (result == null
                      || !result.ReturnSuccess
                      || !result.ResultSuccess
                      || string.IsNullOrEmpty(result.Prepay_Id)
                      || string.IsNullOrEmpty(result.Code_Url))
                    {
                        return new ComposeJsApiParameterResult()
                        {
                            ResultCode = "1",
                            ResultMsg = "获取PrepayId 或 Code_url 失败,错误代码:" + result.Return_Code + ",错误信息：" + result.Return_Msg
                        };
                    }
                    var codeUrl = result.Code_Url;
                    return new ComposeJsApiParameterResult()
                    {
                        ResultCode = "0",
                        ResultMsg = "",
                        Parameter = codeUrl
                    };
                }

            }
            catch (Exception ex)
            {
                return new ComposeJsApiParameterResult()
                {
                    ResultCode = "1",
                    ResultMsg = "通讯失败, 异常信息：" + JsonConvert.SerializeObject(ex)
                };
            }
        }
        /// <summary>
        /// 微信退款
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>

        public static DoRefundResult DoRefund(string outTradeNo, string transactionId, string outRefundNo, int totalFee, int refundFee)
        {
           // Logger.ErrorFormat("退费:{0},{1}，{2}，{3},{4}", outTradeNo, transactionId, outRefundNo, totalFee, refundFee);
            var wxResponse = "";
            try
            {
                UnifiedWxPayModel model = UnifiedWxPayModel.CreateUnifiedModel(WeixinPayV3Info.AppId, WeixinPayV3Info.MchId,
                  WeixinPayV3Info.Key);
                string postData = model.CreateOrderRefundXml(outTradeNo, transactionId,
                    totalFee.ToString(), outRefundNo, refundFee.ToString());
                //退款需要用到证书
                string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
                 
               var message = RefundHelper.PostXmlResponse<RefundMessage>(url, postData,
                    ConfigurationManager.AppSettings["KeyAddr"].ToStringOrDefault()+  @"PartnerCertFile\apiclient_cert.p12", WeixinPayV3Info.MchId, out wxResponse);

                var response = new DoRefundResult();

                if (!message.Success)
                {
                    response.ResultCode = "1";
                    response.ResultMsg = "通讯失败或验签失败" + wxResponse;

                    return response;
                }

                response.OutRefundNo = message.Out_Refund_No;
                response.OutTradeNo = message.Out_Trade_No;
                response.Partner = WeixinPayV3Info.MchId;
                response.RecvUserId = "";
                response.RecvUserName = "";
                switch (message.Refund_Channel.ToLower())
                {
                    case "original":
                        response.RefundChannel = 1;
                        break;
                    case "balance":
                        response.RefundChannel = 0;
                        break;
                    default:
                        response.RefundChannel = 1;
                        break;
                }
                response.RefundFee = message.Refund_Fee.ToInt32OrDefault(0);
                response.RefundId = message.Refund_Id;
                response.TransactionId = message.Transaction_Id;
                response.ResultMsg = message.Return_Msg;
                response.RefundStatus = 9;

                response.ResultCode = "0";
                response.ResultMsg = wxResponse;
                using (var ctx = new HzfyWeiXinEntities())
                {
                    var rlog = new WxPayRefundLog();
                    rlog.OutTradeNo = outTradeNo;
                    rlog.RefundFee = totalFee;
                    rlog.OutRefundNo = outRefundNo;
                    rlog.TransactionId = transactionId;
                    rlog.RecCreateDt = DateTime.Now;
                    rlog.RefundStatus = 0;
                    rlog.RefundId = response.RefundId;
                    ctx.WxPayRefundLog.Add(rlog);
                    ctx.SaveChanges();
                }
                return response;
            }
            catch (Exception ex)
            {
                return new DoRefundResult()
                {
                    ResultCode = "1",
                    ResultMsg = JsonConvert.SerializeObject(ex) + wxResponse
                };
            }
        }

        /// <summary>
        /// 发货通知
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>

        public static DoDeliveryNotifyResult DoDeliveryNotify(string openId, string transId, string outTradeNo, string deliverTime,
                  string deliverResult, string deliverMsg,int retryCount=0)
        {
            
            var wxPayHelper = new WxPayHelper(WeixinPayV3Info.AppId, WeixinPayV3Info.Key, WeixinPayV3Info.MchId);
            var deliverTimestamp = ((deliverTime.ToDateTimeOrDefault().ToUniversalTime().Ticks - 621355968000000000) / 10000000).ToString();
            var parameters = new Dictionary<string, string>();
            parameters.Add("appid", WeixinPayV3Info.AppId);
            parameters.Add("openid", openId);
            parameters.Add("transid", transId);
            parameters.Add("out_trade_no", outTradeNo);
            parameters.Add("deliver_timestamp", deliverTimestamp);
            parameters.Add("deliver_status", deliverResult);
            parameters.Add("deliver_msg", deliverMsg);
            var appSignature = wxPayHelper.GetBizSign(parameters);
            var sendingData = new
            {
                appid = WeixinPayV3Info.AppId,
                openid = openId,
                transid = transId,
                out_trade_no = outTradeNo,
                deliver_timestamp = deliverTimestamp,
                deliver_status = deliverResult,
                deliver_msg = deliverMsg,
                app_signature = appSignature,
                sign_method = "sha1"
            };
            var accessToken = AccessTokenContainer.TryGetAccessToken(WeixinPayV3Info.AppId, WeixinPayV3Info.AppSecret);
            var url = String.Format("https://api.weixin.qq.com/pay/delivernotify?access_token={0}", accessToken);
            try
            {
                using (var httpClient = new HttpClient())
                {
                    var mpResponse = JsonConvert.DeserializeObject<JObject>(httpClient.PostAsJsonAsync(url, sendingData).Result.Content.ReadAsStringAsync().Result);
                    return new DoDeliveryNotifyResult
                    {
                        ResultCode = mpResponse["errcode"].ToObject<string>(),
                        ResultMsg = mpResponse["errmsg"].ToObject<string>(),
                    };
                }
            }
            catch (Exception ex)
            {

                if (retryCount <= 1)
                {
                    retryCount++;
                    return DoDeliveryNotify(openId, transId, outTradeNo, deliverTime, deliverResult, deliverMsg, retryCount);
                }
                return new DoDeliveryNotifyResult
                {
                    ResultCode = "1",
                    ResultMsg = "通讯失败"
                };
            }
        }

        /// <summary>
        /// 告警通知
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
      
        public static ParseAlarmResult ParseAlarm(string postData)
        {
            
            var xmlDoc = new XmlDocument();
            var alarmResponse = new ParseAlarmResult();

            try
            {
                xmlDoc.LoadXml(postData);
                var xmlNode = xmlDoc.SelectSingleNode("/xml");
                var appId = xmlNode.SelectSingleNode("AppId").InnerText;
                var errorType = xmlNode.SelectSingleNode("ErrorType").InnerText;
                var description = xmlNode.SelectSingleNode("Description").InnerText;
                var alarmContent = xmlNode.SelectSingleNode("AlarmContent").InnerText;
                var timestamp = xmlNode.SelectSingleNode("TimeStamp").InnerText;
                var appSignature = xmlNode.SelectSingleNode("AppSignature").InnerText;
                var signMethod = xmlNode.SelectSingleNode("SignMethod").InnerText;

                alarmResponse.ResultCode = "0";
                alarmResponse.AppId = appId;
                alarmResponse.ErrorType = errorType;
                alarmResponse.Description = description;
                alarmResponse.AlarmContent = alarmContent;
                alarmResponse.TimeStamp = timestamp;
                alarmResponse.AppSignature = appSignature;
                alarmResponse.SignMethod = signMethod;

                var wxPayHelper = new WxPayHelper(WeixinPayV3Info.AppId, WeixinPayV3Info.Key, WeixinPayV3Info.MchId);
                var parameters = new Dictionary<string, string>();
                parameters.Add("AppId", appId);
                parameters.Add("ErrorType", errorType);
                parameters.Add("Description", description);
                parameters.Add("AlarmContent", alarmContent);
                parameters.Add("TimeStamp", timestamp);

                var calSign = wxPayHelper.GetBizSign(parameters);
                if (calSign != appSignature)
                {
                    alarmResponse.ResultCode = "1";
                    alarmResponse.ResultMsg = String.Format("验签失败，正确签名为：{0}", calSign);
                }

            }
            catch (Exception ex)
            {
                alarmResponse.ResultCode = "1";
                alarmResponse.ResultMsg = ex.Message;
            }

            return alarmResponse;
        }

        /// <summary>
        /// 维权通知
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
 
        public static ParseFeedBackResult ParseFeedBack(string postData)
        {
           
            var xmlDoc = new XmlDocument();
            var feedBackResponse = new ParseFeedBackResult();

            try
            {
                xmlDoc.LoadXml(postData);
                var xmlNode = xmlDoc.SelectSingleNode("/xml");

                var openId = xmlNode.SelectSingleNode("OpenId").InnerText;
                var appId = xmlNode.SelectSingleNode("AppId").InnerText;
                var timestamp = xmlNode.SelectSingleNode("TimeStamp").InnerText;
                var msgType = xmlNode.SelectSingleNode("MsgType").InnerText.Trim();
                var feedbackId = xmlNode.SelectSingleNode("FeedBackId").InnerText;
                var reason = xmlNode.SelectSingleNode("Reason").InnerText;
                var appSignature = xmlNode.SelectSingleNode("AppSignature").InnerText;
                var signMethod = xmlNode.SelectSingleNode("SignMethod").InnerText;

                feedBackResponse.ResultCode = "0";
                feedBackResponse.OpenId = openId;
                feedBackResponse.AppId = appId;
                feedBackResponse.TimeStamp = timestamp;
                feedBackResponse.MsgType = msgType;
                feedBackResponse.FeedBackId = feedbackId;
                feedBackResponse.Reason = reason;
                feedBackResponse.AppSignature = appSignature;
                feedBackResponse.SignMethod = signMethod;

                if (msgType == "request")
                {
                    var transId = xmlNode.SelectSingleNode("TransId").InnerText;
                    var solution = xmlNode.SelectSingleNode("Solution").InnerText;
                    var extInfo = xmlNode.SelectSingleNode("ExtInfo").InnerText;

                    feedBackResponse.TransId = transId;
                    feedBackResponse.Solution = solution;
                    feedBackResponse.ExtInfo = extInfo;
                    feedBackResponse.PicItems = new List<ParseFeedBackResult.PicItem>();

                    var picInfoNode = xmlNode.SelectSingleNode("PicInfo");
                    if (picInfoNode != null)
                    {
                        var picItemNodes = picInfoNode.SelectNodes("item/PicUrl");
                        if (picItemNodes != null)
                        {
                            foreach (XmlNode node in picItemNodes)
                            {
                                feedBackResponse.PicItems.Add(new ParseFeedBackResult.PicItem
                                {
                                    Url = node.InnerText
                                });
                            }
                        }
                    }
                }

                var wxPayHelper = new WxPayHelper(WeixinPayV3Info.AppId, WeixinPayV3Info.Key, WeixinPayV3Info.MchId);
                var parameters = new Dictionary<string, string>();
                parameters.Add("AppId", appId);
                parameters.Add("TimeStamp", timestamp);
                parameters.Add("OpenId", openId);

                var calSign = wxPayHelper.GetBizSign(parameters);
                if (calSign != appSignature)
                {
                    feedBackResponse.ResultCode = "1";
                    feedBackResponse.ResultMsg = String.Format("验签失败，正确签名为：{0}", calSign);
                }

                return feedBackResponse;
            }
            catch (Exception ex)
            {
                feedBackResponse.ResultCode = "1";
                feedBackResponse.ResultMsg = ex.Message;
            }

            return feedBackResponse;
        }

        /// <summary>
        /// 支付结果通知 notify_url
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>

        public static ParsePayNotifyResult ParsePayNotify(Uri requestUrl, string postData)
        {

            var response = new ParsePayNotifyResult();
            var successMsg = new ReturnMessage() { Return_Code = "SUCCESS", Return_Msg = "" };
            var failMsg = new ReturnMessage() { Return_Code = "FAIL", Return_Msg = "" };
            response.SuccessResponse = successMsg.ToXmlString();
            response.FailResponse = failMsg.ToXmlString();
            string xmlString = postData;
            //try
            //{
            var xmlSerializer = new XmlSerializer(typeof(NotifyMessage));
            var message = (NotifyMessage)(xmlSerializer.Deserialize(new StringReader(xmlString)));

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlString);

            Dictionary<string, string> dic = new Dictionary<string, string>();
            string sign = string.Empty;
            foreach (XmlNode node in doc.FirstChild.ChildNodes)
            {
                if (node.Name.ToLower() != "sign")
                    dic.Add(node.Name, node.InnerText);
                else
                    sign = node.InnerText;
            }

            UnifiedWxPayModel model = UnifiedWxPayModel.CreateUnifiedModel(WeixinPayV3Info.AppId, WeixinPayV3Info.MchId, WeixinPayV3Info.Key);
            if (model.ValidateMD5Signature(dic, sign))
            {
                if (message.ResultSuccess)
                {
                    response.ResultCode = "0";
                    response.ResultMsg = "";
                    response.PayOrder = new ParsePayNotifyResult.OrderInfo()
                    {
                        Partner = WeixinPayV3Info.MchId,
                        TradeState = "0",
                        TradeMode = "-1",
                        BankType = message.Bank_Type,
                        TotalFee = message.Total_Fee.ToString(),
                        TransactionId = message.Transaction_Id,
                        OutTradeNo = message.Out_Trade_No,
                        TimeEnd = message.Time_End
                    };

                    response.PayUser = new ParsePayNotifyResult.UserInfo()
                    {
                        AppId = message.AppId,
                        AppSignature = sign,
                        OpenId = message.OpenId,
                        IsSubscribe = message.Is_Subscribe
                    };
                    return response;
                }
                else
                {
                    response.ResultCode = "1";
                    response.ResultMsg = string.Format("err_code:{0},err_code_des:{1}", message.Err_Code, message.Err_Code_Des);
                    return response;
                }
            }
            else
            {
                response.ResultCode = "2";
                response.ResultMsg = "签名未通过";
                return response;
            }


            //}
            //catch (Exception ex)
            //{
            //    response.ResultCode = "1";
            //    response.ResultMsg = JsonConvert.SerializeObject(ex);
            //    return response;
            //}
        }


        /// <summary>
        /// 订单查询
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>

        public static OrderQueryResult OrderQuery(string outTradeNo)
        {

            //这里应先判断服务器 订单支付状态，如果接到通知，并已经支付成功，就不用 执行下面的查询了
            UnifiedWxPayModel model = UnifiedWxPayModel.CreateUnifiedModel(WeixinPayV3Info.AppId, WeixinPayV3Info.MchId, WeixinPayV3Info.Key);
            var postXml = model.CreateOrderQueryXml(outTradeNo);
            string url = "https://api.mch.weixin.qq.com/pay/orderquery";
            var message = HttpClientHelper.PostXmlResponse(url, postXml);
            //此处主动查询的结果，只做查询用（不能作为支付成功的依据）

            XmlDocument document = new XmlDocument();
            document.LoadXml(message);
            var node = document.SelectSingleNode("/xml/return_code");
            var response = new OrderQueryResult();
            if ((node == null ? "" : node.InnerText).ToLower() != "success")
            {

                response.ResultCode = "1";
                node = document.SelectSingleNode("/xml/return_msg");
                response.ResultMsg = node == null ? "" : node.InnerText;

            }
            node = document.SelectSingleNode("/xml/result_code");
            if ((node == null ? "" : node.InnerText).ToLower() != "success")
            {

                response.ResultCode = "1";
                node = document.SelectSingleNode("/xml/err_code");
                response.ResultMsg = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/err_code_des");
                response.ResultMsg = response.ResultMsg + "||" + (node == null ? "" : node.InnerText);
            }
            else
            {
                response.ResultCode = "0";
                response.ResultMsg = "";
                node = document.SelectSingleNode("/xml/attach");
                response.Attach = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/appid");
                response.AppId = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/bank_type");
                response.BankType = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/cash_fee");
                response.CashFee = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/cash_fee_type");
                response.CashFeeType = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/device_info");
                response.DeviceInfo = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/fee_type");
                response.FeeType = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/out_trade_no");
                response.OutTradeNo = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/is_subscribe");
                response.IsSubscribe = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/mch_id");
                response.MchId = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/nonce_str");
                response.NonceStr = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/openid");
                response.OpenId = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/sign");
                response.Sign = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/time_end");
                response.TimeEnd = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/total_fee");
                response.TotalFee = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/trade_state");
                response.TradeState = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/trade_state_desc");
                response.TradeStateDesc = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/trade_type");
                response.TradeType = node == null ? "" : node.InnerText;
                node = document.SelectSingleNode("/xml/transaction_id");
                response.TransactionId = node == null ? "" : node.InnerText;

            }
            return response;
        }
        /// <summary>
        /// 退款明细查询
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>

        public static DoRefundQueryResult DoRefundQuery(string outTradeNo,string transactionId,string outRefundNo,string refundId)
        {
            
            var refundHelper = new RefundQueryHelper(WeixinPayV3Info.AppId, WeixinPayV3Info.Key, WeixinPayV3Info.MchId, @"PartnerCertFile\apiclient_cert.p12", WeixinPayV3Info.MchId);
            RefundQueryResult normalRefundQueryResult;
            var normalRefundQueryParam = new RefundQueryParam
            {
                OutTradeNo = outTradeNo,
                TransactionId = transactionId,
                OutRefundNo = outRefundNo,
                RefundId = refundId
            };

            var resultCode = refundHelper.DoRefundQuery(normalRefundQueryParam, out normalRefundQueryResult);
            var response = new DoRefundQueryResult();
            if (resultCode == 2)
            {
                response.ResultCode = "1";
                response.ResultMsg = "通讯失败或验签失败";

                return response;
            }

            response.ResultCode = "0";
            response.ResultMsg = normalRefundQueryResult.RetMsg;
            response.Partner = normalRefundQueryResult.Partner;
            response.OutTradeNo = normalRefundQueryResult.OutTradeNo;
            response.TransactionId = normalRefundQueryResult.TransactionId;
            response.RefundCount = normalRefundQueryResult.RefundCount;

            var refundOrders = normalRefundQueryResult.RefundOrderResults.Select(refundOrderResult => new RefundOrder
            {
                OutRefundNo = refundOrderResult.OutRefundNo,
                RefundId = refundOrderResult.RefundId,
                RefundChannel = refundOrderResult.RefundChannel,
                RefundFee = refundOrderResult.RefundFee,
                RefundState = refundOrderResult.RefundState,
                RecvUserId = refundOrderResult.RecvUserId,
                RecvUserName = refundOrderResult.RecvUserName
            }).ToList();

            response.RefundOrders = refundOrders;

            return response;
        }

        #region 刷卡支付
        /// <summary>
        /// 刷卡支付
        /// </summary>
        /// <param name="tradeName"></param>
        /// <param name="tradeNo"></param>
        /// <param name="totalFee"></param>
        /// <param name="authCode"></param>
        /// <param name="clientIp"></param>
        /// <param name="attach"></param>
        /// <returns></returns>
        public static MicroPayResult MicroPay(string tradeName, string tradeNo, string totalFee, string authCode,
            string clientIp, string attach)
        {


            var wxResponse = "";
            try
            {
                UnifiedWxPayModel model = UnifiedWxPayModel.CreateUnifiedModel(WeixinPayV3Info.AppId,
                    WeixinPayV3Info.MchId,
                    WeixinPayV3Info.Key);
                string postXml = model.CreateMicroPayXml(tradeName, tradeNo,
                    totalFee, authCode, clientIp, attach);
                //退款需要用到证书
                string url = "https://api.mch.weixin.qq.com/pay/micropay";


                var message = HttpClientHelper.PostXmlResponse(url, postXml);
                //此处主动查询的结果，只做查询用（不能作为支付成功的依据）

                XmlDocument document = new XmlDocument();
                document.LoadXml(message);
                var node = document.SelectSingleNode("/xml/return_code");
                var response = new MicroPayResult();
                response.ResultMsg = "";
                if ((node?.InnerText ?? "").ToLower() != "success")
                {

                    response.ResultCode = "1";
                    node = document.SelectSingleNode("/xml/return_msg");
                    response.ResultMsg = node?.InnerText ?? "";

                }
                node = document.SelectSingleNode("/xml/result_code");
                if ((node?.InnerText ?? "").ToLower() != "success")
                {

                    response.ResultCode = "1";
                    node = document.SelectSingleNode("/xml/err_code");
                    var errcode = node?.InnerText ?? "";
                    if (!string.IsNullOrEmpty(response.ResultMsg))
                    {
                        response.ResultMsg = response.ResultMsg + (string.IsNullOrEmpty(errcode) ? "" : ("||" + errcode));
                    }
                    else
                    {
                        response.ResultMsg = node?.InnerText ?? "";
                    }
                    if ((node?.InnerText ?? "").ToUpper() == "USERPAYING")
                    {
                        response.ResultCode = "2";
                    }
                    node = document.SelectSingleNode("/xml/err_code_des");

                    var errcodedesc = node?.InnerText ?? "";
                    if (!string.IsNullOrEmpty(response.ResultMsg))
                    {
                        response.ResultMsg = response.ResultMsg + (string.IsNullOrEmpty(errcodedesc) ? "" : ("||" + errcodedesc));
                    }
                    else
                    {
                        response.ResultMsg = node?.InnerText ?? "";
                    }

                }
                else
                {
                    response.ResultCode = "0";
                    response.ResultMsg = "";
                    node = document.SelectSingleNode("/xml/attach");
                    response.Attach = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/appid");
                    response.AppId = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/bank_type");
                    response.BankType = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/cash_fee");
                    response.CashFee = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/cash_fee_type");
                    response.CashFeeType = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/device_info");
                    response.DeviceInfo = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/fee_type");
                    response.FeeType = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/out_trade_no");
                    response.OutTradeNo = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/is_subscribe");
                    response.IsSubscribe = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/mch_id");
                    response.MchId = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/nonce_str");
                    response.NonceStr = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/openid");
                    response.OpenId = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/sign");
                    response.Sign = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/time_end");
                    response.TimeEnd = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/total_fee");
                    response.TotalFee = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/trade_state");
                    response.TradeType = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/transaction_id");
                    response.TransactionId = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/settlement_total_fee");
                    response.SettlementTotalFee = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/coupon_fee");
                    response.CouponFee = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/detail");
                    response.Detail = node?.InnerText ?? "";
                }
                return response;
            }
            catch (Exception ex)
            {
                return new MicroPayResult()
                {
                    ResultCode = "2",
                    ResultMsg = JsonConvert.SerializeObject(ex) + wxResponse
                };
            }
        }

        /// <summary>
        /// 撤销订单
        /// </summary>
        public static ReverseResult Reverse(string tradeNo, string transactionId)
        {
            var wxResponse = "";
            try
            {
                UnifiedWxPayModel model = UnifiedWxPayModel.CreateUnifiedModel(WeixinPayV3Info.AppId,
                    WeixinPayV3Info.MchId,
                    WeixinPayV3Info.Key);
                string postXml = model.ReverseXml(tradeNo, transactionId);
                //退款需要用到证书
                string url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";


                //var message = HttpClientHelper.PostXmlResponse(url, postXml);
                var message = RefundHelper.PostXmlResponse<ReverseMessage>(url, postXml,
                 ConfigurationManager.AppSettings["KeyAddr"].ToStringOrDefault(), WeixinPayV3Info.MchId, out wxResponse);
                //此处主动查询的结果，只做查询用（不能作为支付成功的依据）

                XmlDocument document = new XmlDocument();
                document.LoadXml(wxResponse);
                var node = document.SelectSingleNode("/xml/return_code");
                var response = new ReverseResult();
                if ((node?.InnerText ?? "").ToLower() != "success")
                {

                    response.ResultCode = "1";
                    node = document.SelectSingleNode("/xml/return_msg");
                    response.ResultMsg = node?.InnerText ?? "";

                }
                node = document.SelectSingleNode("/xml/result_code");
                if ((node?.InnerText ?? "").ToLower() != "success")
                {

                    response.ResultCode = "1";
                    node = document.SelectSingleNode("/xml/err_code");
                    response.ResultMsg = node?.InnerText ?? "";
                    node = document.SelectSingleNode("/xml/err_code_des");
                    response.ResultMsg = response.ResultMsg + "||" + (node?.InnerText ?? "");

                    node = document.SelectSingleNode("/xml/recall");
                    if ((node?.InnerText ?? "").ToUpper() == "Y")
                    {
                        response.ResultCode = "2";
                    }
                }

                return response;
            }
            catch (Exception ex)
            {
                return new ReverseResult()
                {
                    ResultCode = "2",
                    ResultMsg = JsonConvert.SerializeObject(ex) + wxResponse
                };
            }
        }

        #endregion

    }


  
}